<!DOCTYPE html>
<html lang="cn" style="">
<head>
	<title>[7.10]-phalapi-进阶篇4(notrom进阶以及事务操作) | PhalApi - PHP轻量级开源接口框架</title>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<link rel="icon" href="http://webtools.qiniudn.com/dog_catch.png" type="image/x-icon" />
	<meta name="description" content="PhalApi是一个PHP轻量级开源接口框架。我们致力于将PhalApi维护成像恒星一样：不断更新，保持生气；为接口负责，为开源负责！让后台接口开发更简单！">
	<meta name="keywords" content="PhalApi,phalapi,phalapi接口开发,后台接口开发框架,后台接口开发,接口开发,接口框架,开源接口框架,PHP后台接口开发,PHP接口开发,PHP接口框架,PHP后台接口框架,phalapi官网,PHP接口框架,php接口开发框架,php接口开发,php web框架">
	<meta name="author" content="dogstar">

	<link rel="stylesheet" type="text/css" href="./../css/screen.css?20150211" />
</head>

<body>

<!-- 最顶部的语言(S) -->
<div class="grid-wrapper navbar desktop-only">
	<div class="grid">
		<div class="grid__cell">
			<ul id="language-switchers" class="navbar__links navbar--left">
				<li class="menu-item"><a title="PhalApi官方网站中文版" href="./" class="menu-item__link">中文版</a></li>
				<li class="menu-item"><a title="English version of PhalApi website" href="#" class="menu-item__link">English</a></li>
			</ul>
			<ul id="util-menu" class="navbar__links navbar--right navbar--vertical-separator">
				<li class="menu-item"><a href="#" class="menu-item__link contact-us-spec">官方交流群：421032344</a></li>
			</ul>
		</div>
	</div>
</div>
<!-- 最顶部的语言(E) -->

<!-- 顶部导航菜单(S) -->
<div class="grid-wrapper desktop-only">
	<div class="grid">
		<div class="grid__cell">
			<div class="header__header-wrapper">
				<a title="PhalApi" href="http://www.phalapi.net" class="header__logo"><img src="http://webtools.qiniudn.com/master-LOGO-20150410_33.jpg" id="tw-logo" alt="PhalApi"></a>
				<ul id="main-menu" class="header__menu">
					<li class="menu-item"><a href="http://qa.phalapi.net/" class="menu-item__link insights-spec" target="_blank">社区</a></li>
					<li class="menu-item"><a href="/download.html" class="menu-item__link insights-spec" target="_blank">下载</a></li>
					<li class="menu-item"><a href="/wikis/" class="menu-item__link events-spec" target="_blank">文档</a></li>
    				<li class="menu-item"><a href="/docs/" class="menu-item__link events-spec" target="_blank">类参考手册</a></li>
					<li class="menu-item"><a href="http://phalapi.oschina.mopaas.com/Public/demo/" class="menu-item__link products-spec" target="_blank">在线体验</a></li>
					<li class="menu-item"><a href="/about.html" class="menu-item__link about-us-spec" target="_blank">关于我们</a></li>
				</ul>
			</div>
		</div>
	</div>
</div>
<!-- 顶部导航菜单(E) -->


    <div class="grid-wrapper">
        <div class="grid">
            <div class="grid__cell">
                <h1>phalapi-进阶篇4(notrom进阶以及事务操作)</h1>
<p><img src="http://webtools.qiniudn.com/master-LOGO-20150410_50.jpg" alt="" /></p>
<h2>前言</h2>
<p><strong><em>先在这里感谢phalapi框架创始人@dogstar,为我们提供了这样一个优秀的开源框架.</em></strong></p>
<p>写本篇教程的起因是在于在交流的时候有位童鞋提出了fetchPairs有BUG,原来一直没有仔细的了解过notorm的细节,趁这次机会主要把notorm之中的一些方便快捷的操作简单的说明一下,以及对与事务操作做一些我自己的简介以及使用notorm如何实现.</p>
<p>附上:</p>
<p>喵了个咪的博客:<a href="w-blog.cn">w-blog.cn</a></p>
<p>官网地址:<a href="http://www.phalapi.net/" title="PhalApi官网"><a href="http://www.phalapi.net/">http://www.phalapi.net/</a></a></p>
<p>开源中国Git地址:<a href="http://git.oschina.net/dogstar/PhalApi/tree/release" title="开源中国Git地址"><a href="http://git.oschina.net/dogstar/PhalApi/tree/release">http://git.oschina.net/dogstar/PhalApi/tree/release</a></a></p>
<h2>1. 进一步了解notorm</h2>
<p>在notorm有很多方便并没有在PhalApi官方文档中有并没有非常详细的介绍过,在这里把一些可能会用到的notorm函数坐下介绍以及功能</p>
<h3>1.1 fetchPairs</h3>
<p>fetchPairs的使用和fetchAll相似但是他有一个特别之处,fetchPairs需要传递一个参数,这个参数是字符串的key值(比如 name id)当传递之后会出现这样的对比效果</p>
<pre><code>DI()-&gt;notorm-&gt;user-&gt;fetchPairs('name');</code></pre>
<p><img src="http://i.imgur.com/kIBqze2.png" alt="" /></p>
<pre><code>DI()-&gt;notorm-&gt;user-&gt;fetchAll('name');</code></pre>
<p><img src="http://i.imgur.com/VZjpvv3.png" alt="" /></p>
<p>大家有看到区别吗?</p>
<p>嗯!是在返回的时候把在之前定义的key值放到了返回数组的key中</p>
<p><strong>提示:在老版本中在使用过程中 Result.php 会有一句 821行的报错需要把</strong></p>
<pre><code>$values = array_values(iterator_to_array($row));
改成
$values = array_values($row);</code></pre>
<h3>1.2 lock</h3>
<p>lock操作是一种锁的行为,对于整表进行锁定,在当前用户释放锁之前此表不能在被操作,lock接受一个bool参数,默认是true锁表,使用如下</p>
<pre><code>$userdb = DI()-&gt;notorm-&gt;user-&gt;lock(); //锁定表
$rs     = $userdb-&gt;fetchAll();</code></pre>
<p>生成的sql语句如下:</p>
<pre><code>SELECT * FROM user FOR UPDATE;</code></pre>
<h3>1.3 加操作</h3>
<p>在很多时候我们会用到,数据库里面某个值+1或者是其他,我们不能在update的时候写入array('key' =&gt; 'key+1')因为在解析sql的时候 key+1 会带上引号作为一个字符串处理,当然是有解决方法的,如下</p>
<pre><code>DI()-&gt;notorm-&gt;user-&gt;where('id', 1)-&gt;update(array('sum' =&gt; new NotORM_Literal("sum + 1")));</code></pre>
<p>这样就可以生成不带引号的操作了</p>
<pre><code>UPDATE user SET phone = sum + 1 WHERE (id = 1);</code></pre>
<h3>1.4 group</h3>
<p>group是去重操作,在notorm里面也封装的有,我们可以使用group用于统计有多少同名的用户等一些统计操作,或者是找出库里面不重复的城市名</p>
<pre><code>DI()-&gt;notorm-&gt;user-&gt;select('name , count(*) as count')-&gt;group('name')-&gt;fetchAll();</code></pre>
<p>会获得如下结果</p>
<p><img src="http://i.imgur.com/aYJ229P.png" alt="" /></p>
<h3>1.5 快速函数sum,count,max,min</h3>
<p>在我们使用过程中虽然使用这类操作不是很多,但是使用notorm的快速函数依然感觉很方便,</p>
<pre><code>  return DI()-&gt;notorm-&gt;user-&gt;sum('id');  //做加法
  return DI()-&gt;notorm-&gt;user-&gt;max('id');  //获取这个key中最大的值
  return DI()-&gt;notorm-&gt;user-&gt;min('id');  //获取这个key中最小的值
  return DI()-&gt;notorm-&gt;user-&gt;count();    //统计一共几条数据</code></pre>
<h2>2. 事务操作</h2>
<p>其实很大一部分使用事务的目的是应为害怕并发的情况下导致,对数据库造成重复的操作,比如如下场景:</p>
<p>应用审核,有两个管理者对同一个应用审核,一个成功一个失败,然后是同时请求过来的,一起到了查询应用状态发现都是未审核,然后都去进行了审核操作,这个时候两个操作返回的都是审核成功,但是有一个人会看到审核状态和自己的审核结果不同,这个就是问题了,大部分解决此类问题时都会考虑到使用数据库事务操作,其实对于事务操作我的建议是能不用尽量不要使用,我简单聊一下我的几个观点</p>
<ol>
<li>
<p>是否真的那么重要,对于上面的问题也许乍一看上去感觉,这样怎么可以呢,但是仔细想一想,这两个操作都是属于我们管理者的正常的操作,真正对于业务来说我认为是没有问题的,当然这是因为影响不大,如果是付款,一个订单从两个地方同时付款然后都发现是未付款,然后都进行了付款,这种业务就必须有处理方式了,所以是否使用事务要看业务是否非常需求</p>
</li>
<li>
<p>概率是怎么样的,对于一个程序来说,两条请求刚好通过了查询过程,一同到了修改的时候,不管是什么场景发生这种并发冲突的可能性是极其微小的,我觉得几乎可以忽略(当然前提是重要性没有那么的高,我们不能<strong>以偏概全</strong>)</p>
</li>
<li><strong>曲线救国</strong>其实我们可以使用其他方式避免这种问题,我们可以把我们需要验证条件加入到Update的条件中这样两条语句总归会有一条语句执行失败</li>
</ol>
<p>那么我们使用notorm中解决此类需要用到事务的问题呢</p>
<p>notorm提供了常规的事务操作如下</p>
<pre><code> //第一步：先指定待进行事务的数据库（通过获取一个notorm表实例来指定；否则会提示：PDO There is no active transaction）
 $user = DI()-&gt;notorm-&gt;user;
 //第二步：开启事务开关（此开关会将当前全部打开的数据库都进行此设置）
 DI()-&gt;notorm-&gt;transaction = 'BEGIN';

 //第三步：进行数据库操作
 $user-&gt;insert(array('name' =&gt; 'test3',));
 $user-&gt;insert(array('name' =&gt; 'test4',));

 //第四：提交/回滚
 DI()-&gt;notorm-&gt;transaction = 'COMMIT';
 //DI()-&gt;notorm-&gt;transaction = 'ROLLBACK';</code></pre>
<p>还有一种处理方式就是在操作之前进行lock锁表</p>
<pre><code>$user = DI()-&gt;notorm-&gt;user;
$user-&gt;lock();                                                  
$user-&gt;insert(array('name' =&gt; 'test3',));
$user-&gt;insert(array('name' =&gt; 'test4',));</code></pre>
<p>这两种方式大家可以自行取舍</p>
<p>注:在phalapiV1.31版本后有自带提供事务操作可参考文档</p>
<h2>3. 总结</h2>
<p>在本小节中,对于notorm之中的一些特别的封装函数进行了一系列的介绍,以及对于事务提出了我的看法以及观点,和使用notorm的解决方案,希望看了这篇教程的童鞋对你的日常开发有所帮助</p>
<p>注:笔者能力有限有说的不对的地方希望大家能够指出,也希望多多交流!</p>
<p><strong>官网QQ交流群:421032344  欢迎大家的加入!</strong></p>
<h4><a href="/wikis/%5b7.9%5d-phalapi-%e8%bf%9b%e9%98%b6%e7%af%873(%e8%87%aa%e5%8a%a8%e5%8a%a0%e8%bd%bd%e5%92%8c%e6%8b%a6%e6%88%aa%e5%99%a8).html">上一章</a>   <a href="/wikis/">文档首页</a>   <a href="/wikis/%5b7.11%5d-phalapi-%e8%bf%9b%e9%98%b6%e7%af%875(%e6%95%b0%e6%8d%ae%e5%ba%93%e8%af%bb%e5%86%99%e5%88%86%e7%a6%bb).html">下一章</a></h4>
            </div>
        </div>
    </div>
    
 <!-- 广告位 -->
<div class="grid-wrapper desktop-only">
	<p align="center">
		<a href="http://7qnay5.com1.z0.glb.clouddn.com/走向开源的第一年%20-%20PhalApi%202015年度开源总结%20-%20官方出品%20-%2020151214.pdf" target="blank"><img width="950" height="100" src="http://7qnay5.com1.z0.glb.clouddn.com/PhalApi20151213-2.jpg"></a>
		<a href="http://qa.phalapi.net" target="blank"><img width="950" height="100" src="http://7qnay5.com1.z0.glb.clouddn.com/qa_ad_20150615.jpg"></a>
	</p>
</div>

<!-- footer(S) -->
<div class="grid-wrapper footer">
	<div id="footer" class="grid">	

		<div class="grid__cell unit-1-2--lap">
			<h3><img src="http://webtools.qiniudn.com/master-LOGO-20150410_50.jpg" height="50"></h3>
            <p>
            <font size="3px;">PhalApi是一个PHP轻量级后台接口开发框架。<br/>
                我们致力于将PhalApi维护成像恒星一样：不断更新，保持生气；为接口负责，为开源负责！让后台接口开发更简单！
            </font>
			</p>
			<p align="left">
				<font size="2px">&copy;2015 PhalApi All Rights Reserved. 粤ICP备15028808号</font>
				<script type="text/javascript">var cnzz_protocol = (("https:" == document.location.protocol) ? " https://" : " http://");document.write(unescape("%3Cspan id='cnzz_stat_icon_1255326144'%3E%3C/span%3E%3Cscript src='" + cnzz_protocol + "s4.cnzz.com/z_stat.php%3Fid%3D1255326144%26show%3Dpic' type='text/javascript'%3E%3C/script%3E"));</script>
			</p>
		</div>	

		<div class="grid__cell unit-1-2--lap">
			<h3>在这里，特别感谢</h3>

			<div class="nav">
				<ul class="footer__nav">
					<li class="menu-item"><a href="http://www.oschina.net/" class="menu-item__link" target="_blank">开源中国</a></li>
					<li class="menu-item"><a href="http://www.phalconphp.com/en/" class="menu-item__link" target="_blank">Phalcon</a></li>
					<li class="menu-item"><a href="https://phpunit.de/manual/3.7/zh_cn/automating-tests.html" class="menu-item__link" target="_blank">PHPUnit</a></li>
					<li class="menu-item"><a href="http://www.thoughtworks.com/cn/" class="menu-item__link" target="_blank">ThoughtWorks</a></li>
				</ul>
			</div>

            <div id="perspectives">
                <div class="email-signup">
                    <strong><a href="https://auth.alipay.com/login/index.htm" target="_blank">支付宝&nbsp;</a>开源捐赠：</strong>chanzonghuang@gmail.com
                </div>
            </div>

			<p>
				<!-- JiaThis Button BEGIN -->
				<div id="ckepop">
				<span class="jiathis_txt">分享到：</span>
				<a class="jiathis_button_tsina">新浪微博</a>
				<a href="http://www.jiathis.com/share" class="jiathis jiathis_txt jiathis_separator jtico jtico_jiathis" target="_blank">更多</a>
				<a class="jiathis_counter_style"></a>
				</div>
				<script type="text/javascript" src="http://v2.jiathis.com/code/jia.js" charset="utf-8"></script>
				<!-- JiaThis Button END -->
				
				&nbsp;&nbsp;
				<a target="_blank" href="http://shang.qq.com/wpa/qunwpa?idkey=19a39de7950ee074cdc92d8684962666107d8401191789b9ac3bda80b9efb705"><img border="0" src="http://pub.idqqimg.com/wpa/images/group.png" alt="PhalApi交流群" title="PhalApi交流群"></a>
			</p>
		</div>
	</div>
</div>
<!-- footer(E) -->

</body>

<script type="text/javascript">var cnzz_protocol = (("https:" == document.location.protocol) ? " https://" : " http://");document.write(unescape("%3Cspan id='cnzz_stat_icon_1254743218'%3E%3C/span%3E%3Cscript src='" + cnzz_protocol + "w.cnzz.com/q_stat.php%3Fid%3D1254743218' type='text/javascript'%3E%3C/script%3E"));</script>

<script type="text/javascript">
  (function(w,d,t,u,n,s,e){w['SwiftypeObject']=n;w[n]=w[n]||function(){
  (w[n].q=w[n].q||[]).push(arguments);};s=d.createElement(t);
  e=d.getElementsByTagName(t)[0];s.async=1;s.src=u;e.parentNode.insertBefore(s,e);
  })(window,document,'script','//s.swiftypecdn.com/install/v2/st.js','_st');

  _st('install','aizsj_k8pkmMmqLWzayG','2.0.0');
</script>

</html>